import classnames from "classnames";
import React from "react";
import { Diff, getChangeKey, HunkData, parseDiff } from "react-diff-view";
import "react-diff-view/style/index.css";
import { DiffPart, IDiffProps } from "../constants";
import "./index.less";
export default (props: IDiffProps) => {
  const { schemaNew, schemaOld, comments, show = false } = props;
  const oldJson = JSON.stringify(schemaOld, null, 2);
  const newJson = JSON.stringify(schemaNew, null, 2);
  const diff = require("diff");
  const diffText = () => {
    // 准备 diff 文本的头部
    // react-diff-view库固定title
    const diffTextLines = [
      "--- a/file.json",
      "+++ b/file.json",
      `@@ -1,${oldJson.split("\n").length} +1,${newJson.split("\n").length} @@`,
    ];

    const diffs = diff.diffJson(oldJson, newJson);
    diffs.forEach((part: DiffPart) => {
      const type = part.added ? "+" : part.removed ? "-" : " ";
      const lines = part.value.split("\n");
      lines.forEach((line: string, index: number) => {
        if (line?.trim() !== "" || index !== lines.length - 1) {
          diffTextLines.push(type + line);
        }
      });
    });
    // 返回合并的结果
    return diffTextLines.join("\n");
  };

  const files = parseDiff(diffText());
  // 增加校验
  const getWidgets = (hunks: HunkData[]) => {
    const changes = hunks.reduce<HunkData["changes"]>(
      (result, { changes }) => [...result, ...changes],
      [] as HunkData["changes"]
    );
    const longLines = changes.filter(({ content }) => content.length > 0);
    return longLines.reduce((widgets, change) => {
      const changeKey = getChangeKey(change);

      return {
        ...widgets,
        [changeKey]: (
          <>
            {comments?.map(
              (
                comment: {
                  key: string;
                  error:
                    | string
                    | number
                    | bigint
                    | boolean
                    | React.ReactElement<
                        unknown,
                        string | React.JSXElementConstructor<any>
                      >
                    | Iterable<React.ReactNode>
                    | React.ReactPortal
                    | Promise<
                        | string
                        | number
                        | bigint
                        | boolean
                        | React.ReactPortal
                        | React.ReactElement<
                            unknown,
                            string | React.JSXElementConstructor<any>
                          >
                        | Iterable<React.ReactNode>
                        | null
                        | undefined
                      >
                    | null
                    | undefined;
                },
                index: React.Key | null | undefined
              ) => {
                const isLastComment = index === comments.length - 1;
                return (
                  show &&
                  comment.key === changeKey &&
                  comment.error && (
                    <div
                      key={index}
                      className={classnames(
                        "border-y-medium  border-x-0 border-solid border-secondary",
                        isLastComment ? "border-b-0" : "border-b-medium"
                      )}
                    >
                      <div className="text-state-failure p-l">
                        {comment.error}
                      </div>
                    </div>
                  )
                );
              }
            )}
          </>
        ),
      };
    }, {});
  };
  return (
    <div className={"codeDiff"}>
      {files.map(({ hunks }, i) => (
        <Diff
          diffType={show ? "delete" : "modify"}
          key={i}
          hunks={hunks}
          widgets={getWidgets(hunks)}
          viewType="split"
          className="diff"
        />
      ))}
    </div>
  );
};
